#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>

#include "definition.h"

#define OUT_BUF_SIZE 4096
#define KEY_SIZE (24)

extern int base64_encode(unsigned char* in, unsigned int in_size, unsigned char* out, unsigned int *out_size);
extern int base64_decode(unsigned char* in, unsigned int in_size, unsigned char* out, unsigned int *out_size);
extern int transform_from_url(const char* url, unsigned int in_size, char* out, unsigned int *out_size);
extern int transform_to_url(const char* in, unsigned int in_size, char* out, unsigned int *out_size);
extern bool _encrypt(const unsigned char* in, unsigned int in_size, unsigned char* out, unsigned int *out_size, unsigned char key[KEY_SIZE]);
extern bool _decrypt(const unsigned char* in, unsigned int in_size, unsigned char* out, unsigned int *out_size, unsigned char key[KEY_SIZE]);


static char* key = "Kylin\tActivation\tRevised";

/*
 * encrypt_hardware_info, encrypt hardware information
 * return NO_ERROR if succeeds, or return error number
 */
int encrypt_hardware_info(const char* hw_info, unsigned int in_size, unsigned char* out, unsigned int *out_size)
{
    int ret;
    bool result;

    unsigned char base64_out[OUT_BUF_SIZE] = {0};
    char transform_out[OUT_BUF_SIZE] = {0};
    unsigned char crypt_out[OUT_BUF_SIZE] = {0};
    unsigned int  base64_out_size = 0;
    unsigned int  transform_out_size = 0;
    unsigned int  crypt_out_size = 0;


    if(!hw_info || !out || !out_size || (in_size == 0))
        return INFO_ENCRYPT_ERROR;
    *out_size = 0;

    result = _encrypt((unsigned char*)hw_info, in_size, crypt_out, &crypt_out_size, (unsigned char*)key);
    if(!result)
        return SSL_ENCRYPT_ERROR;

    ret = base64_encode(crypt_out, crypt_out_size, (unsigned char*)base64_out, &base64_out_size);
    if(ret != NO_ERROR)
        return ret;

    ret = transform_to_url((char*)base64_out, base64_out_size, transform_out, &transform_out_size);
    if(ret != NO_ERROR)
        return ret;

    memcpy(out, transform_out, transform_out_size);
    *out_size = transform_out_size;

    return NO_ERROR;
}

/*
 * decrypt_hardware_info, decrypt hardware information
 * return NO_ERROR if succeeds, or return error number
 */
int decrypt_hardware_info(const char* encrypted_info, unsigned int in_size, unsigned char* out, unsigned int *out_size)
{
    int ret;
    bool result;

    unsigned char base64_out[OUT_BUF_SIZE] = {0};
    char transform_out[OUT_BUF_SIZE] = {0};
    unsigned char crypt_out[OUT_BUF_SIZE] = {0};
    unsigned int  base64_out_size = 0;
    unsigned int  transform_out_size = 0;
    unsigned int  crypt_out_size = 0;


    if(!encrypted_info || !out || !out_size || (in_size == 0))
        return INFO_DECRYPT_ERROR;
    *out_size = 0;

    ret = transform_from_url(encrypted_info, in_size, transform_out, &transform_out_size);
    if(ret != NO_ERROR)
        return ret;

    ret = base64_decode((unsigned char*)transform_out, transform_out_size, base64_out, &base64_out_size);
    if(ret != NO_ERROR)
        return ret;

    result = _decrypt(base64_out, base64_out_size, crypt_out, &crypt_out_size, (unsigned char*)key);
    if(!result)
        return SSL_DECRYPT_ERROR;

    memcpy(out, crypt_out, crypt_out_size);
    *out_size = crypt_out_size;

    return NO_ERROR;
}

